package com.iflytek.cosmo.ocr.common.util;

import javax.imageio.ImageIO;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageDecoder;
import com.sun.media.jai.codec.ImageEncoder;

import net.coobird.thumbnailator.Thumbnails;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * 图片处理工具
 * 
 * @author yunsun
 *
 */
@Service
public class ImageUtil {
	 /**
     * 日志记录器
     */
    private static Logger logger = LoggerFactory.getLogger(ImageUtil.class);
    
    private  static  String localtempPath;
    
	
 
	public static  String getLocaltempPath() {
		return localtempPath;
	}
	@Value("${local.tempPath}")
	public void setLocaltempPath(String localtempPath) {
		this.localtempPath = localtempPath;
	}

	/**
	 * pdf格式转换成png格式
	 * @param inputStream 输入流
	 * @return OutputStream 输出流列表
	 */
	public static List<OutputStream> pdfToPng(InputStream inputStream) {
		List<OutputStream> list = new ArrayList<>();
		PDDocument doc = null;
		try {
			doc = PDDocument.load(inputStream);
			PDFRenderer renderer = new PDFRenderer(doc);
			int pageCount = doc.getNumberOfPages();
			for (int i = 0; i < pageCount; i++) {
				BufferedImage image = renderer.renderImage(i, 2f);
				OutputStream outputStream = new ByteArrayOutputStream();
				ImageIO.write(image, "png", outputStream);
				list.add(outputStream);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (doc != null) {
				try {
					doc.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return list;
	}
	
	/**
	 * 获取pdf页数
	 * @param inputStream 输入流
	 * @return pdf页数
	 */
	public static int getPdfPageCount(InputStream inputStream) {
		int pageCount = 0;
		PDDocument doc = null;
		try {
			doc = PDDocument.load(inputStream);
			pageCount = doc.getNumberOfPages();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (doc != null) {
				try {
					doc.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return pageCount;
	}
	
	/**
	 * tif格式转换成jpg格式
	 * @param inputstream 输入流
	 * @return OutputStream 输出流
	 */
	public static OutputStream tifToJpg(InputStream inputstream) {
		try {
			ByteArrayOutputStream outputStream = null;
			if (inputstream != null) {
				outputStream = new ByteArrayOutputStream();
				ImageDecoder decoder = ImageCodec.createImageDecoder("tiff", inputstream, null);
				ImageEncoder encoder = ImageCodec.createImageEncoder("jpeg", outputStream, null);
				encoder.encode(decoder.decodeAsRenderedImage());
				decoder = null;
				encoder = null;
			}
			return outputStream;

		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

    public static OutputStream tiff2Jpg(InputStream inputStream) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            BufferedImage tif = ImageIO.read(inputStream);
            ImageIO.write(tif, "png", outputStream);
            return outputStream;
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

	/**
	 * 通过opencv jNi接口方式压缩图片 解决大图片OutOfMemory问题
	 * <br>
	 * 适用场景:	<br>
	 * 调用方式:	<br>
	 * 业务逻辑说明<br>
	 *
	 * @param inputstream
	 * @param rate
	 * @param fileName
	 * @return
	 * @throws Exception
	 * @autho dgyu
	 * @time 2019年9月16日 下午7:57:52
	 */
	public static ByteArrayOutputStream cutImage(InputStream inputstream, double rate,
			String fileName) throws Exception {
		logger.info(
				"java.library.path=" + System.getProperty("java.library.path"));
		try {
			String writePath = localtempPath;
			String tempWritePath = writePath + "tempWritePath";

			File dictoryfile = new File(writePath);
			// 如果文件夹不存在则创建
			if (!dictoryfile.exists() && !dictoryfile.isDirectory()) {
				logger.info("目录：" + writePath + "不存在，创建之");
				dictoryfile.mkdir();
			}

			dictoryfile = new File(tempWritePath);
			// 如果文件夹不存在则创建
			if (!dictoryfile.exists() && !dictoryfile.isDirectory()) {
				logger.info("目录：" + tempWritePath + "不存在，创建之");
				dictoryfile.mkdir();
			}
			dictoryfile = null;
			String writePathFile = writePath + fileName;
			String tempWritePathFile = tempWritePath + fileName;

			// 文件流写道本地磁盘
			File targetFile = new File(writePathFile);
			FileUtils.copyInputStreamToFile(inputstream, targetFile);

			System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
			Mat src = Imgcodecs.imread(writePathFile);
			// 读取图像到矩阵中
			if (src.empty()) {
				throw new Exception("no file");
			}
			Mat dst = src.clone();
			// 复制矩阵进入dst
			double scale = rate;
			double width = src.width();
			double height = src.height();
			// 压缩图片
			Imgproc.resize(src, dst, new Size(width * scale, height * scale));
			Imgcodecs.imwrite(tempWritePathFile, dst);

			// 压缩后的图片转换为ByteArrayOutputStream
			File file = new File(tempWritePathFile);
			ByteArrayOutputStream out = new ByteArrayOutputStream();;
			FileInputStream in = new FileInputStream(file);
			byte[] b = new byte[1024];
			int i = 0;
			while ((i = in.read(b)) != -1) {
				out.write(b, 0, b.length);
			}
			in.close();
			out.close();
			targetFile.delete();
			file.delete();
			return out;

		} catch (Exception e) {
			logger.info("压缩图片发生异常:", e);
		}
		return null;
	}

	
	/**
	 * 根据压缩比例对图片进行压缩
	 * @param inputstream 文件流
	 * @param rate 压缩比例
	 * @return 压缩图片
	 */
	public static ByteArrayOutputStream reduceImgByRate(InputStream inputstream, double rate){
        BufferedImage srcImage = null;
        BufferedImage destImage = null;
		try {
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
			if(inputstream != null){
				// 从流里将图片写入缓冲图片区
				ImageIO.setUseCache(false);
				srcImage = ImageIO.read(inputstream);
				inputstream.close();
				// 得到源图片宽
				int srcWidth = srcImage.getWidth(null);
				// 得到源图片高
				int srcHeight = srcImage.getHeight(null);
				
				//目标图片宽
				int destWidth = (int) (srcWidth * rate);
				//目标图片高
				int destHeight = (int) (srcHeight * rate);
	            // 构造一个类型为预定义图像类型之一的 BufferedImage
				destImage = new BufferedImage(destWidth, destHeight, BufferedImage.TYPE_3BYTE_BGR);

	            //绘制图像  getScaledInstance表示创建此图像的缩放版本，返回一个新的缩放版本Image,按指定的width,height呈现图像
	            //Image.SCALE_SMOOTH,选择图像平滑度比缩放速度具有更高优先级的图像缩放算法。
				destImage.getGraphics().drawImage(srcImage.getScaledInstance(destWidth, destHeight, Image.SCALE_SMOOTH), 0, 0, null);

				ImageIO.write(destImage, "jpg", outputStream);

				return outputStream;
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
				if(null  != destImage){
                destImage.flush();
                destImage = null;

				}
				if(null  != destImage){
					srcImage.flush();
					srcImage = null;
				}
		}
		return null;
	}
	
	/**
	 * 使用google的Thumbnails对图片进行压缩
	 * <br>
	 * 适用场景:	<br>
	 * 调用方式:	<br>
	 * 业务逻辑说明<br>
	 *
	 * @param inputstream
	 * @param rate
	 * @return
	 * @autho dgyu
	 * @time 2019年9月10日 下午3:01:18
	 */
	public static ByteArrayOutputStream reduceImgByThumbnailsRate(InputStream inputstream, double rate){
		try {
			/**
			 * scale 比例
			 */
			ByteArrayOutputStream os = new ByteArrayOutputStream();
			Thumbnails.of(inputstream).scale(rate).outputFormat("png").toOutputStream(os);
			return os;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 获取图片宽度和高度
	 * @param inputstream 文件流
	 * @return 图片宽度和高度
	 */
	public static int[] getImgWidthHeight(InputStream inputstream) {
		int result[] = { 0, 0 };
		try {
			// 从流里将图片写入缓冲图片区
			BufferedImage image = ImageIO.read(inputstream);
			// 得到源图片宽
			result[0] = image.getWidth(null);
			// 得到源图片高
			result[1] = image.getHeight(null);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

    /**
     * 将 base64 编码的图片内容写入本地临时文件, 该临时文件会在系统退出后自动删除
     *
     * @param base64Str base64 编码的图片内容
     *
     * @return 临时文件
     *
     * @throws IOException
     */
    public static File base64ToTempFile(String base64Str) throws IOException {
        if (StringUtils.isBlank(base64Str)) {
            return null;
        }

        Pair<String, String> contentAndExtention = parseBase64Str(base64Str);
        Path tempFile = Files.createTempFile("截图", '.' + contentAndExtention.getRight());
        byte[] bytes = Base64.getDecoder().decode(contentAndExtention.getLeft());
        Files.write(tempFile, bytes, StandardOpenOption.WRITE);

        File tempImageFile = tempFile.toFile();
        // 系统退出时自动删除该临时文件
        tempImageFile.deleteOnExit();
        return tempImageFile;
    }

    /**
     * 将 base64 编码的图片内容写入指定文件, 该临时文件会在系统退出后自动删除
     *
     * @param base64Str      base64 编码的图片内容
     * @param targetFilePath 待写入的文件路径
     *
     * @return 写入的文件
     *
     * @throws IOException
     */
    public static File base64ToFile(String base64Str, String targetFilePath) throws IOException {
        if (StringUtils.isAnyBlank(base64Str, targetFilePath)) {
            return null;
        }

        Pair<String, String> contentAndExtention = parseBase64Str(base64Str);
        byte[] bytes = Base64.getDecoder().decode(contentAndExtention.getLeft());
        Path filePath = Paths.get(targetFilePath);
        Files.write(filePath, bytes, StandardOpenOption.WRITE);
        return filePath.toFile();
    }

    /**
     * 解析 base64 格式的图片内容
     *
     * @param base64Str base64 格式的图片, 形如: "...==" 或 "iVBORw0KGgoA...=="
     *
     * @return 图片内容, 图片扩展名(默认 png)
     */
    public static Pair<String, String> parseBase64Str(String base64Str) {
        String[] strings = StringUtils.split(base64Str, ',');

        String extension;
        switch (strings[0]) {
            case "data:image/jpeg;base64":
                extension = "jpeg";
                break;
            case "data:image/jpg;base64":
                extension = "jpg";
                break;
            case "data:image/png;base64":
                extension = "png";
                break;
            default:
                extension = "png";
                break;
        }

        String content = strings.length == 1 ? strings[0] : strings[1];
        return Pair.of(content, extension);
    }

    /**
     * 生成截图上传文件的文件名
     *
     * @return 形如: "截图_20190501123000"
     */
    public static String genCaptureFileName() {
        return "截图_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
    }
}
